﻿/*
 * Project: IV:MP GUI Editor (http://code.google.com/p/ivmp-gui-editor)
 * Code license: GNU Lesser GPL (http://www.gnu.org/copyleft/lesser.html)
 * 
 * Authors: CrackHD
 * Description: window for logging or outputing some text
 */

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Threading;
using System.Globalization;

namespace IvmpEditor
{
    public partial class wndTextOutput : Window
    {
        Editor EditorMgr;
        BackgroundWorker m_bgwCompile;

        public wndTextOutput(Editor mgr)
        {
            InitializeComponent();
            EditorMgr = mgr;
        }

        public bool IsCloseable
        {
            get;
            set;
        }
        public ICompiler Compiler
        {
            get;
            private set;
        }
        public bool IsCompilingNow
        {
            get { return m_bgwCompile != null && m_bgwCompile.IsBusy; }
        }
        
        public new void Show()
        {
            if (IsVisible)
                Focus();
            else
                base.Show();
        }
        public void Log(string text)
        {
            txtText.AppendText(string.Format("[{0}:{1}] {2}{3}",
                DateTime.Now.Hour.ToString().PadLeft(2, '0'), DateTime.Now.Minute.ToString().PadLeft(2, '0'), 
                text, Environment.NewLine));

            // Scrols text box text to end!
            txtText.CaretIndex = txtText.Text.Length;
            var rect = txtText.GetRectFromCharacterIndex(txtText.CaretIndex);
            txtText.ScrollToHorizontalOffset(rect.Right);
        }
        public bool StartCompilation(EDocument doc)
        {
            // Check we have no compilation atm
            if (IsCompilingNow)
            {
                Log(Properties.Resources.L_CompileReject);
                return false;
            }

            // Ensure document saved
            if (!doc.Save())
            {
                Log(Properties.Resources.L_CompileRevoke);
                return false;
            }

            // Log some info
            txtText.Clear();
            Log(string.Format(Properties.Resources.L_FileName, doc.File.Name, doc.File.FullName));
            Log(string.Format(Properties.Resources.L_FileEncoding, doc.TextEncoding.EncodingName, doc.TextEncoding.CodePage));

            // Configure compiler:
            this.Compiler = doc.Type.Compiler;
            if (Compiler is PawnCompiler)
            {
                // Specify includes dir for pawn:
                var pawnCompiler = (PawnCompiler)Compiler;
                pawnCompiler.IncludesDirectoryPath = Settings.PawnIncludesDir;
            }
            else if (Compiler is SquirrelCompiler)
            {
                // Specify executable name of squirrel compiler (version)
                var squirrelCompiler = (SquirrelCompiler)Compiler;
                squirrelCompiler.EXEName = Settings.SquirrelEXEName;
            }
            txtInfoText.Text = Compiler.InfoText;

            // Create and run thread:
            m_bgwCompile = new BackgroundWorker();
            m_bgwCompile.WorkerSupportsCancellation = true;
            m_bgwCompile.DoWork += 
                delegate(object bgw_sender, DoWorkEventArgs e)
                {
                    // Get compile arguments:
                    var trdArgs = e.Argument as object[];
                    var sourceFileName = trdArgs[0] as string;
                    var sourceEncoding = trdArgs[1] as Encoding;
                    Thread.CurrentThread.CurrentUICulture = (CultureInfo) trdArgs[2];

                    // Setting up events:
                    Compiler.CompilationStarted     += Compiler_CompilationStarted;
                    Compiler.SetStatus              += Compiler_SetStatus;
                    Compiler.FatalError             += Compiler_FatalError;
                    Compiler.CompilationFinished    += Compiler_CompilationFinished;

                    // Compile:
                    var timer = Stopwatch.StartNew();
                    Compiler.Compile(sourceFileName, sourceEncoding);

                    // Removing events:
                    Compiler.CompilationStarted     -= Compiler_CompilationStarted;
                    Compiler.SetStatus              -= Compiler_SetStatus;
                    Compiler.FatalError             -= Compiler_FatalError;
                    Compiler.CompilationFinished    -= Compiler_CompilationFinished;

                    timer.Stop();
                    if (Compiler.IsCompileDone)
                        LogInvoke(string.Format(Properties.Resources.L_CompileDone, (int)timer.Elapsed.TotalSeconds));
                    Compiler = null;
                };
            m_bgwCompile.RunWorkerCompleted +=
                delegate
                {
                    // Dispose compile thread...
                    this.m_bgwCompile = null;
                };
            btnCloseText.Text = Properties.Resources.L_Abort;
            m_bgwCompile.RunWorkerAsync(
                new object[] { doc.File.FullName, doc.TextEncoding, Thread.CurrentThread.CurrentUICulture });
            return true;
        }

        void btnClose_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
        void Window_Closing(object sender, CancelEventArgs e)
        {
            // Abort compiler work if we have one:
            if (IsCompilingNow)
            {
                Log(Properties.Resources.L_Aborting);
                Dispatcher.Invoke((Action<string, bool>)SetStopButtonText, Properties.Resources.L_Aborting, false);
                Compiler.RequestAbort();

                e.Cancel = true;
                return;
            }
            else if (IsCloseable)
                return;

            // Instead of closing, hiding for secondary use in future.
            e.Cancel = true;
            this.Hide();
            EditorMgr.MainWindow.Focus();//FIX: fixes strange behavior of main window when child window closed (lost focus)...
        }
        void LogInvoke(string text)
        {
            Dispatcher.Invoke((Action<string>)Log, text);
        }
        void Compiler_CompilationStarted(ICompiler sender)
        {
            LogInvoke(Properties.Resources.L_CompileStarted);
        }
        void Compiler_SetStatus(ICompiler sender, string text)
        {
            LogInvoke(text.Trim());
        }
        void Compiler_FatalError(ICompiler sender, string text)
        {
            LogInvoke(string.Format(Properties.Resources.L_ErrorU, text));
        }
        void Compiler_CompilationFinished(ICompiler sender)
        {
            if (!sender.IsCompileDone)
            {
                if (Compiler.IsCompileAborted)
                    LogInvoke(Properties.Resources.L_CompileCancelled);
                else
                    LogInvoke(Properties.Resources.L_CompileFailed);
            }
            Dispatcher.Invoke((Action<string, bool>)SetStopButtonText, Properties.Resources.L_Close, true);
        }
        void SetStopButtonText(string newText, bool enabled)
        {
            btnCloseText.Text = newText;
            btnClose.IsEnabled = enabled;
        }
    }
}
